#pragma once
#include "tinyxml/tinyxml.h"


bool registerClass(const TCHAR * name, WNDPROC wndProc);


const unsigned short c_UnicodeHeader = 0xfeff;
const unsigned short c_Enter = 0x0a;
const char * const c_XmlSplit  = "|";

void string2wstring(wstring & ws, const string & s);
void wstring2string(string & s, const wstring & ws);
void sprintf(string & s, const char * formatString, ...); 
void sprintf(wstring & s, const wchar_t * formatString, ...);
template <typename StringType>
void upperCase(StringType & s)
{
	std::transform(s.begin(), s.end(), s.begin(), toupper);
}
template <typename StringType>
void lowerCase(StringType & s)
{
	std::transform(s.begin(), s.end(), s.begin(), tolower);
}


template <typename StringType>
size_t searchSubString(const StringType & source, const StringType & sub, size_t begin = 0)
{
	return source.find(sub, begin);
}
template <typename StringType>
int compare(const StringType & s1, const StringType & s2, bool caseSensitive = true)
{
	if (caseSensitive)
		return s1.compare(s2); 
	else
	{
		StringType tmp1 = s1;
		StringType tmp2 = s2;
		lowerCase(tmp1);
		lowerCase(tmp2);

		return tmp1.compare(tmp2);
	}
}

template <typename StringType, typename CharType>
int compare(const StringType & s1, const CharType * s2, bool caseSensitive = true)
{
	wstring s2_ = s2;
	return compare(s1, s2_, caseSensitive);
}



void trimLeft(wstring & str);
void trimLeft(string & str);
void trimRight(wstring & str);
void trimRight(string & str);


template <typename StringType, typename CharType>
size_t replaceSubString(StringType & source, const CharType * pat, const CharType * newPat, size_t times = 1)
{
	StringType pattern = pat, newPattern = newPat;
	size_t count = 0;
	const size_t nsize = newPattern.length();
	const size_t psize = pattern.length();

	for(size_t pos = source.find(pattern, 0); 
		pos != std::string::npos;
		pos = source.find(pattern, pos + nsize))
	{
		source.replace(pos, psize, newPattern);
		count++;

		if (count == times)
			break;
	}

	return count;
}

template <typename StringType, typename CharType>
size_t replaceAllSubString(StringType & source, const CharType * pat, const CharType * newPat)
{
	StringType pattern = pat, newPattern = newPat;
	size_t count = 0;
	const size_t nsize = newPattern.length();
	const size_t psize = pattern.length();

	for(size_t pos = source.find(pattern, 0); 
		pos != std::string::npos;
		pos = source.find(pattern, pos + nsize))
	{
		source.replace(pos, psize, newPattern);
		count++;
	}

	return count;
}

template <typename StringType>
void trim(StringType & s)
{
	trimLeft(s);
	trimRight(s);
}

template <typename StringType, typename CharType>
void split(vector<StringType> & v, const StringType & source, const CharType * deli)
{			
	StringType delimitation = deli;
	for (size_t start = 0; ;)
	{
		StringType::size_type pos = source.find_first_of(delimitation, start);
		if (pos == StringType::npos)
		{
			StringType tmp = source.substr(start);
			if (!tmp.empty())
				v.push_back(tmp);
			break;
		}
		else
		{
			StringType tmp = source.substr(start, pos - start);
			if (!tmp.empty())
				v.push_back(tmp);
			start = pos + 1;
			if (start == source.length())
				break;
		}
	}
}

void dateTimeString2SystemTime(const string & str, SYSTEMTIME & st);

void log(const wchar_t * str);
void closeLog();

const wstring & getAppPathW();
const string & getAppPathA();
#ifdef UNICODE
	#define getAppPath getAppPathW
#else
	#define getAppPath getAppPathA
#endif

void putFileToPath(string & output, const char * file, const char * path);
void putFileToPath(wstring & output, const wchar_t * file, const wchar_t * path);
void putFileToAppPath(string & output, const char * file);
void putFileToAppPath(wstring & output, const wchar_t * file);
void getPath(wstring & path, const wstring & fullPath);


enum SampleType{STANDARD = 0, SAMPLE, SAVED};


template <typename T>
T myAbs(T t)
{
	return t >= 0 ? t : -t;
}

template <typename T>
T myMax(T t1, T t2)
{
	return t1 > t2 ? t1 : t2;
}

template <typename T>
T myMaxAbs(T t1, T t2)
{
	return myMax(myAbs(t1), myAbs(t2));
}

struct MenuData
{
	int mIdOrPosition;
	bool mByPosition;
	int mTextIndex;
	MenuData * mSubMenu;
};


#define doModalAndStorePointer(DialogType, pointer, returnValue) DialogType dlg;\
													pointer = &dlg;\
													returnValue = dlg.DoModal();\
													pointer = 0;

#define WM_NS_SETLANGUAGE WM_USER + 6000
#define WM_NS_TABLECHILD_CHANGE WM_USER + 6010

#define type1ToType2(t1, t2, data, toType2) type12Type2(t1, t2, data, sizeof(data) / sizeof(data[0]), toType2)
#define type1ToStringCaseSensitive(t1, t2, data, toType2) type12Type2(t1, t2, data, sizeof(data) / sizeof(data[0]), toType2, true)

template<typename T1, typename T2>
bool type12Type2(T1 & t1, T2 & t2, const void * lookupData, size_t count, bool toType2 = true)
{
	struct Data
	{
		T1 mT1;
		T2 mT2;
	};
	const Data * data = (const Data *) lookupData;

	if (toType2)
	{
		for (size_t i = 0; i < count; ++i)
		{
			if (data[i].mT1 == t1)
			{
				t2 = data[i].mT2;
				return true;
			}
		}
	}
	else
	{
		for (size_t i = 0; i < count; ++i)
		{
			if (data[i].mT2 == t2)
			{
				t1 = data[i].mT1;
				return true;
			}
		}
	}
	return false;
}

template <typename T1>
bool type12Type2(T1 & t1, wstring & t2, const void * lookupData, size_t count, bool toType2 = true, bool caseSensitive = false)
{
	struct Data
	{
		T1 mT1;
		const TCHAR * mT2;
	};
	const Data * data = (const Data *) lookupData;

	if (toType2)
	{
		for (size_t i = 0; i < count; ++i)
		{
			if (data[i].mT1 == t1)
			{
				t2 = data[i].mT2;
				return true;
			}
		}
	}
	else
	{
		for (size_t i = 0; i < count; ++i)
		{
			int n;
			if (caseSensitive)
				n = _tcscmp(data[i].mT2, t2.c_str());
			else
				n = _tcsicmp(data[i].mT2 ,t2.c_str());
			if (n == 0)
			{
				t1 = data[i].mT1;
				return true;
			}
		}
	}
	return false;
}

class Job;
void generateDataName(wstring & name, const TCHAR * format, int index, const TCHAR * originalName = 0);
size_t getFloatStringLength(float f, size_t numberCount);

#define WM_INITNAME WM_USER + 5555

void getExePath(wstring & path);
void getFileWithAppPath(string & fullPathFile, const string & theFile);
void getFileWithAppPath(wstring & fullPathFile, const wstring & theFile);
void getSettingsFile(string & theFile);
void getLogFile(wstring & theFile);

void getLocalTimeString(wstring & str);
void getTimeString(wstring & str, 
				   unsigned short year,
				   unsigned char month,
				   unsigned char day,
				   unsigned char hour,
				   unsigned char minute, 
				   unsigned char second);
void systemTime2wstring(wstring & str, const SYSTEMTIME & st);
bool isValidDate(unsigned short year, unsigned short month, unsigned short day);
bool isValidTime(unsigned short hour, unsigned short minute, unsigned short second);

struct ReportCell
{
	ReportCell(const TCHAR * text = 0) {if (text) mText = text;}
	wstring mText;
};

typedef vector<ReportCell> ReportRow;
struct ReportTable
{
	bool empty() const {return mData.empty();}
	size_t getDataCount() const {return mData.size();}
	size_t getColumnCount() const {return mColumnWidth.size();}
	const ReportCell & getCell(size_t i, size_t j) const {return mData[i][j];}
	void addRow(const ReportRow & row) {mData.push_back(row);}
	void addColumnWidth(size_t width) {mColumnWidth.push_back(width);}
	void clearData() {mData.clear();}

	vector<ReportRow> mData;
	vector<unsigned int> mColumnWidth;
};


void hex2wstring(wstring & s, const vector<unsigned char> & v, size_t spaceNum);
size_t wstring2Hex(vector<unsigned char> & hex, const wstring & str);
void exitThread(HANDLE h, void * exitTag1, unsigned int timeout);
bool isMessagePassed(const vector<unsigned char> & m, const vector<unsigned char> & pattern, const vector<unsigned char> & mask, bool passFilter);
void pathAdd(wstring & base, const wstring & sub);
HKEY openKey(HKEY parent, const wchar_t * path);
bool getKeyValue(HKEY key, const wchar_t * name, wstring & v);
bool getKeySubNum(HKEY key, DWORD & subKeyNum, DWORD & subValueNum);
void completeImageFileName(wstring & f);
bool wstring2bool(const wstring & str);
const wstring & bool2wstring(bool b);
void setFont(CWnd * wnd, HFONT font, bool redraw  = true );
void copyToClipboard(const CString & s);
void copyToClipboard(CWnd * wnd);

bool isAllZero(const void * para, size_t theSize);
//void CRect2Rect(Rect & rt1, const CRect & rt2);
//void Rect2CRect(CRect & rt1, const Rect & rt2);


void systemtimeDecSeconds(SYSTEMTIME & st, int seconds);
void systemtimeAddSeconds(SYSTEMTIME & st, int seconds);
int mySend(SOCKET sock, const char * data, int theSize, int flag);
#define RED RGB(255, 0, 0) 
#define BLACK RGB(0, 0, 0)
#define BLUE RGB(0, 0, 255)

void showInf(const wchar_t * str, COLORREF color = BLACK, int fontAdd = 0);
